package service

import (
	"errors"
	"github.com/gin-gonic/gin"
	"github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth/user"
	"github.com/go-admin-team/go-admin-core/sdk/service"
	"gorm.io/gorm"
	"strconv"
	"strings"
	"time"
	models2 "tuowei.com/app/admin/models"
	serviceadmin "tuowei.com/app/admin/service"
	dtoadmin "tuowei.com/app/admin/service/dto"
	"tuowei.com/app/api/models"
	apimodels "tuowei.com/app/api/models"
	"tuowei.com/app/api/service/dto"
	apidto "tuowei.com/app/api/service/dto"
	"tuowei.com/common/actions"
	cDto "tuowei.com/common/dto"
	"tuowei.com/pkg/xlog"
)

type ApiStudent struct {
	service.Service
}

func (e *ApiStudent) Insert(req *dto.SysStudentInsertReq) (lastID int, err error) {
	var student models.SysStudent
	req.Generate(&student)
	err = e.Orm.Create(&student).Error
	if err != nil {
		xlog.Error(err)
		return 0, err
	}
	return student.Id, nil
}

func (e *ApiStudent) GerStudentInfo(student *models.SysStudent, lastId int) error {
	var err error
	err = e.Orm.Preload("Class").Preload("College").First(student, lastId).Error
	if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
		err = errors.New("查看对象不存在或无权查看")
		xlog.Errorf("db error: %s", err)
		return err
	}
	return nil
}

func (e *ApiStudent) GetUserInfoByPhone(student *models.SysStudent, phone string) error {
	var err error
	err = e.Orm.Where("phone = ?", phone).First(&student).Error
	return err
}

func (e *ApiStudent) Update(req *dto.SysStudentUpdateReq, studentID int) error {
	var err error
	// 验证一下有没有别的用户有这个手机号
	otherStudent := new(models.SysStudent)
	err = e.Orm.Table(models.SysStudent{}.TableName()).
		Where("id != ?", studentID).
		Where("phone = ?", req.Phone).First(otherStudent).Error
	if err != nil {
		xlog.Error(err)
		if !errors.Is(err, gorm.ErrRecordNotFound) {
			xlog.Error(err)
			return err
		}
	} else {
		return errors.New("该手机号已经被另外的账号绑定")
	}
	var student *models.SysStudent
	err = e.Orm.First(&student, studentID).Error
	if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
		err = errors.New("查看对象不存在或无权查看")
		xlog.Errorf("db error: %s", err)
		return err
	}
	times, _ := time.Parse("2006-01-02 15:04:05", req.ShenBenTime)
	updateStudent := &models.UpdateSysStudent{
		Model:        student.Model,
		Name:         student.Name,
		Phone:        student.Phone,
		Province:     student.Province,
		District:     student.District,
		City:         student.City,
		Area:         student.Area,
		CollegeId:    student.CollegeId,
		ShenBenTime:  times,
		Faculty:      student.Faculty,
		Major:        student.Major,
		ModelTime:    student.ModelTime,
		IsRegistered: 1,
	}

	req.Generate(updateStudent)
	e.Orm.Table(student.TableName()).Save(updateStudent)
	return nil
}

func (e *ApiStudent) Delete(studentID int) error {
	var err error
	var data models.SysStudent
	data.Id = studentID

	db := e.Orm.Model(&data).Delete(&data, data.Id)
	if db.Error != nil {
		err = db.Error
		e.Log.Errorf("Delete error: %s", err)
		return err
	}
	if db.RowsAffected == 0 {
		err = errors.New("无权删除该数据")
		return err
	}
	return nil
}

func (e *ApiStudent) UpdatePayBalance(req *dto.SysPayBalanceReq, studentID int, c *gin.Context) error {
	var err error
	var student *models.SysStudent
	err = e.Orm.First(&student, studentID).Error
	if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
		err = errors.New("查看对象不存在或无权查看")
		xlog.Errorf("db error: %s", err)
		return err
	}
	tableName := ""
	b := student.Balance
	if req.Change == 1 { //增加
		b = student.Balance + req.Balance
	} else if req.Change == 2 {
		switch req.OrderType {
		case "OnlineOrder", "LiveOrder":
			req.TableName = "sys_online_order"
			tableName = "sys_online_order"
			var data models2.OnlineOrder
			err = e.Orm.Debug().Table(data.TableName()).Where("order_number = ?", req.OrderNumber).
				First(&data).Error
			if err != nil {
				xlog.Error(err)
				return err
			}
			req.Balance = float32(data.Price)

		case "MaterialOrder":
			req.TableName = "sys_material_order"
			tableName = "sys_material_order"
			var data models2.MaterialOrder
			err = e.Orm.Debug().Table(data.TableName()).Where("order_number = ?", req.OrderNumber).
				First(&data).Error
			if err != nil {
				xlog.Error(err)
				return err
			}
			req.Balance = float32(data.Price)

		default:
			//订单列表进来付款,不知道OrderType
			type PriceU struct {
				Price    float64 `json:"price"`
				UserType string  `json:"user_type"`
			}
			priceU := PriceU{}

			err = e.Orm.Table("sys_online_order").Select("price", "user_type").Where("order_number=?", req.OrderNumber).Scan(&priceU).Error
			if err != nil {
				xlog.Error(err)
			}

			if priceU.Price != 0 {
				req.TableName = "sys_online_order"
				tableName = "sys_online_order"
				switch priceU.UserType {
				case "online":
					req.OrderType = "OnlineOrder"
				case "live":
					req.OrderType = "LiveOrder"
				}
				break
			}
			TotalAmount := 0.00
			err = e.Orm.Table("sys_material_order").Select("price").Where("order_number=?", req.OrderNumber).Scan(&TotalAmount).Error
			if err != nil {
				xlog.Error(err)
			}
			if TotalAmount != 0 {
				req.TableName = "sys_material_order"
				req.OrderType = "MaterialOrder"
				tableName = "sys_material_order"
			} else {
				xlog.Error(err)
				return errors.New("订单金额为0,请检查订单")
			}
			req.Balance = float32(TotalAmount)
		}

		b = student.Balance - req.Balance
	}

	if b >= 0 {
		err := e.Orm.Table(student.TableName()).Where("id=?", studentID).Update("balance", b).Error
		if err != nil {
			xlog.Errorf("db error: %s", err)
			return err
		}
		switch req.OrderType {
		case "OnlineOrder", "LiveOrder":
			req.TableName = "sys_online_order"
		case "MaterialOrder":
			req.TableName = "sys_material_order"
		}
		if req.Change == 2 {
			//更新订单状态
			switch req.OrderType {
			case "OnlineOrder", "LiveOrder":
				var data models2.OnlineOrder

				err := e.Orm.Table(data.TableName()).Where("order_number=?", req.OrderNumber).Updates(map[string]interface{}{"pay_at": time.Now().Local().Format("2006-01-02T15:04:05.000+08:00"), "status": 5}).Error
				if err != nil {
					xlog.Errorf("db error: %s", err)
					return err
				}
				//更新linkorder
				err = e.Orm.Table("sys_link_order").Where("order_number=?", req.OrderNumber).Update("status", 5).Error
				if err != nil {
					xlog.Errorf("db error: %s", err)
					return err
				}
			case "MaterialOrder":
				var data models2.MaterialOrder
				err := e.Orm.Table(data.TableName()).Where("order_number=?", req.OrderNumber).Updates(map[string]interface{}{"pay_at": time.Now().Local().Format("2006-01-02T15:04:05.000+08:00"), "status": 3}).Error
				if err != nil {
					xlog.Errorf("db error: %s", err)
					return err
				}
				//更新linkorder
				err = e.Orm.Table("sys_link_order").Where("order_number=?", req.OrderNumber).Update("status", 3).Error
				if err != nil {
					xlog.Errorf("db error: %s", err)
					return err
				}

			}
		}
		//
		type Paydb struct {
			Id         int    `json:"id"`
			BuyerId    int    `json:"buyer_id"`
			CourseType string `json:"course_type"`
		}
		paydb := &Paydb{}
		err = e.Orm.Table(req.TableName).Select("id", "buyer_id").Where("order_number=?", req.OrderNumber).Scan(paydb).Error
		if err != nil {
			xlog.Errorf("db error: %s", err)
			return err
		}
		if paydb.BuyerId == 0 {
			xlog.Errorf("db outTradeNo: %s;buyerId:%d", req.OrderNumber, paydb.BuyerId)
			return err
		}
		//余额支付
		if req.Change == 2 {
			//更新学生消费总金额
			type TotalPayS struct {
				TotalPay float64 `json:"total_pay"`
				Name     string  `json:"name"`
				UserType string  `json:"user_type"`
			}
			totalPayS := &TotalPayS{}
			err = e.Orm.Table("sys_student").Select("total_pay", "name", "user_type").Where("id=?", paydb.BuyerId).Scan(&totalPayS).Error
			if err != nil {
				xlog.Errorf("db error: %s", err)
				return err
			}
			if tableName == "sys_online_order" {
				if totalPayS.UserType != "线下" && totalPayS.UserType != "线上" {
					err = e.Orm.Table("sys_student").Where("id=?", paydb.BuyerId).Update("user_type", "线上").Error
					if err != nil {
						xlog.Errorf("db error: %s", err)
						return err
					}
				}

			} else if tableName == "sys_material_order" {
				if totalPayS.UserType == "" {
					err = e.Orm.Table("sys_student").Where("id=?", paydb.BuyerId).Update("user_type", "-").Error
					if err != nil {
						xlog.Errorf("db error: %s", err)
						return err
					}
				}
			}

			totalPayS.TotalPay = totalPayS.TotalPay + float64(req.Balance)
			if totalPayS.TotalPay > 0.00 {
				err := e.Orm.Table("sys_student").Where("id=?", paydb.BuyerId).Update("total_pay", totalPayS.TotalPay).Error
				if err != nil {
					xlog.Errorf("db error: %s", err)
					return err
				}
			}
			//只有在线课程才需要学习
			if req.OrderType == "OnlineOrder" {
				//添加learning-list 订单付款成功之后再入库
				courseId := make([]int, 0)
				err = e.Orm.Table("online_order_course").Select("course_id").Where("order_id=?", paydb.Id).Find(&courseId).Error
				if err != nil {
					xlog.Errorf("db error: %s", err)
					return err
				}
				//线上课程填充班级id
				onlineClassId := 0
				if len(courseId) > 0 {
					for _, c := range courseId {
						var data models.SysCourse
						err = e.Orm.Debug().Table(data.TableName()).Where("course_id = ?", c).
							First(&data).Error
						if err != nil {
							xlog.Errorf("db error: %s", err)
							return err
						}
						onlineClassId = data.OnlineClassId
						//添加learning-list
						s1 := ApiLearningList{}
						s1.Orm = e.Orm
						req1 := apidto.SysLearningListInsertReq{}
						req1.BuyerId = paydb.BuyerId
						req1.CourseId = c
						req1.Name = data.Name
						req1.Cover = data.Cover
						req1.Subject = data.Subject

						list := &apimodels.SysLearningList{}
						err = s1.Insert(&req1, list)
						if err != nil {
							xlog.Errorf("db error: %s", err)
							return err
						}
					}
				}
				if onlineClassId != 0 {
					err = e.Orm.Table("sys_student").Where("id=?", paydb.BuyerId).Update("class_id", onlineClassId).Error
					if err != nil {
						xlog.Errorf("db error: %s", err)
						return err
					}
				}
			}
		}
		//余额明细
		s := SysBalanceDetail{}
		s.Orm = e.Orm
		req1 := dto.SysBalanceDetailInsertReq{}
		// 设置创建人
		req1.SetCreateBy(studentID, "")

		req1.BuyerId = studentID
		req1.Title = req.Title
		req1.BalanceChange = float64(req.Balance)
		req1.Change = req.Change
		req1.BalanceSum = float64(b)
		err = s.Insert(&req1)
		if err != nil {
			xlog.Errorf("db error: %s", err)
			return err
		}
		//todo 特殊返佣，根据分享者id，只有网课

		//返佣
		if req.Change == 2 && req.Balance != 0 {
			ccom := models.SysConfigCommission{}
			err = e.Orm.Table(ccom.TableName()).First(&ccom).Error
			if err != nil {
				xlog.Errorf("db error: %s", err)
				return err
			}
			//根据分享者id， 只有特殊返佣，只有网课才会给分享者返佣，其他的一律按照上级来
			if req.OrderType == "OnlineOrder" {
				type Sharedb struct {
					ShareId       int `json:"share_id"`
					IsBindOffline int `json:"is_bind_offline"`
				}
				sharedb := &Sharedb{}
				err = e.Orm.Table("sys_online_order").Select("share_id", "is_bind_offline").Where("order_number=?", req.OrderNumber).Scan(sharedb).Error
				if err != nil {
					xlog.Errorf("db error: %s", err)
					return err
				}
				if sharedb.ShareId != 0 && sharedb.IsBindOffline == 1 {
					userLabel := ""
					err = e.Orm.Table("sys_student").Select("user_label").Where("id=?", sharedb.ShareId).Scan(&userLabel).Error
					if err != nil {
						xlog.Errorf("db error: %s", err)
						return err
					}
					//校验该网课id是否属于vip等级管理的特殊返佣课程集合里面，否则不返佣
					courseId := make([]int, 0)
					err = e.Orm.Table("online_order_course").Select("course_id").Where("order_id=?", paydb.Id).Find(&courseId).Error
					if err != nil {
						xlog.Errorf("db error: %s", err)
						return err
					}
					if len(courseId) > 0 {
						xlog.Errorf("该订单关联的课程为0,order_id:%s", paydb.Id)
						return errors.New("该订单关联的课程为0")
					}
					//返佣比例
					commissionPercentage := 0.00

					//分享人用户类型，普通，vip，svip
					switch userLabel {
					case "普通":
						if !strings.Contains(ccom.UserCommissionCourseId, strconv.Itoa(courseId[0])) {
							xlog.Errorf("该订单关联的课程未在特殊返佣页面配置-普通,order_id:%s", paydb.Id)
							return errors.New("该订单关联的课程未在特殊返佣页面配置")
						}
						commissionPercentage = ccom.UserCommissionPerSpecial
					case "VIP":
						if !strings.Contains(ccom.VipCommissionCourseId, strconv.Itoa(courseId[0])) {
							xlog.Errorf("该订单关联的课程未在特殊返佣页面配置-vip,order_id:%s", paydb.Id)
							return errors.New("该订单关联的课程未在特殊返佣页面配置")
						}
						commissionPercentage = ccom.VipCommissionPercentageSpecial
					case "SVIP":
						if !strings.Contains(ccom.SVipCommissionCourseId, strconv.Itoa(courseId[0])) {
							xlog.Errorf("该订单关联的课程未在特殊返佣页面配置-svip,order_id:%s", paydb.Id)
							return errors.New("该订单关联的课程未在特殊返佣页面配置")
						}
						commissionPercentage = ccom.SVipCommissionPercentageSpecial
					default:
						xlog.Errorf("db userLabel: %s;sharedb.ShareId:%d", userLabel, sharedb.ShareId)
						return err
					}
					//佣金计算
					com := float64(req.Balance) * commissionPercentage
					//分佣加余额
					//推荐人加佣金
					req2 := dto.SysPayBalanceReq{}
					s2 := ApiStudent{}
					s2.Orm = e.Orm

					req2.Change = 1
					req2.Balance = float32(com)
					req2.Title = "邀请人-" + student.Name
					req2.TableName = tableName
					req2.OrderNumber = req.OrderNumber

					err = s2.UpdatePayBalance(&req2, sharedb.ShareId, c)
					if err != nil {
						xlog.Error(err)
						return err
					}
					//更新订单佣金
					err := e.Orm.Table(req.TableName).Where("order_number=?", req.OrderNumber).Updates(map[string]interface{}{"commission": com}).Error
					if err != nil {
						xlog.Errorf("db error: %s", err)
						return err
					}
					return nil
				}
			}
			if student.Recommender != 0 { //推荐人
				var recommender *models.SysStudent
				err = e.Orm.First(&recommender, student.Recommender).Error
				if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
					err = errors.New("查看对象不存在或无权查看")
					xlog.Errorf("db error: %s", err)
					return err
				}
				//返佣比例
				commissionPercentage := 0.00

				//推荐人用户类型，普通，vip，svip
				switch recommender.UserLabel {
				case "普通":
					commissionPercentage = ccom.UserCommissionPer
				case "VIP":
					commissionPercentage = ccom.VipCommissionPercentage
				case "SVIP":
					commissionPercentage = ccom.SVipCommissionPercentage
				default:
					xlog.Errorf("db userLabel: %s;recommender:%d", recommender.UserLabel, recommender)
					return err
				}
				//佣金计算
				com := float64(req.Balance) * commissionPercentage
				//推荐人加佣金
				req2 := dto.SysPayBalanceReq{}
				s2 := ApiStudent{}
				s2.Orm = e.Orm

				req2.Change = 1
				req2.Balance = float32(com)
				req2.Title = "邀请人-" + student.Name
				req2.TableName = tableName
				req2.OrderNumber = req.OrderNumber

				err = s2.UpdatePayBalance(&req2, recommender.Id, c)
				if err != nil {
					xlog.Error(err)
					return err
				}
				//更新订单佣金
				err := e.Orm.Table(req.TableName).Where("order_number=?", req.OrderNumber).Updates(map[string]interface{}{"commission": com}).Error
				if err != nil {
					xlog.Errorf("db error: %s", err)
					return err
				}
			}
			//增加积分
			ss := SysScore{}
			ss.Orm = e.Orm
			reqs := dto.SysScoreInsertReq{}
			//数据权限检查
			p := actions.GetPermissionFromContext(c)
			// 设置创建人
			reqs.SetCreateBy(user.GetUserId(c), user.GetUserName(c))
			reqs.BuyerId = studentID
			reqs.OrderNumber = req.OrderNumber
			reqs.ScoreChange = float64(req.Balance / 100)
			reqs.Change = 1
			reqs.OrderType = req.OrderType
			switch req.OrderType {
			case "OnlineOrder", "LiveOrder":
				var data models2.OnlineOrder
				err = ss.Orm.Debug().Table(data.TableName()).Where("order_number = ?", req.OrderNumber).
					First(&data).Error
				if err != nil {
					xlog.Error(err)
					return err
				}
				s1 := serviceadmin.SysOrder{}
				s1.Orm = e.Orm
				req1 := dtoadmin.SysOnlineOrderDetailRequest{}
				req1.Id = data.Id
				detail := new(models2.OnlineOrder)
				detail.Id = data.Id
				err = s1.GetOnlineOrderDetail(&req1, p, detail)
				if err != nil {
					xlog.Error(err)
					return err
				}
				if len(detail.Course) >= 1 {
					reqs.Subject = detail.Course[0].Subject
					reqs.Name = detail.Course[0].Name
					reqs.Cover = detail.Course[0].Cover
					reqs.Introduction = detail.Course[0].Introduction
				}

			case "MaterialOrder":
				var data models2.MaterialOrder
				err = ss.Orm.Debug().Table(data.TableName()).Where("order_number = ?", req.OrderNumber).
					First(&data).Error
				if err != nil {
					xlog.Error(err)
					return err
				}

				s2 := serviceadmin.SysOrder{}
				s2.Orm = e.Orm
				req2 := dtoadmin.SysMaterialOrderDetailRequest{}
				req2.Id = data.Id
				detail := new(models2.MaterialOrder)
				detail.Id = data.Id
				err = s2.GetMaterialOrderDetail(&req2, p, detail)
				if err != nil {
					xlog.Error(err)
					return err
				}
				if len(detail.Material) >= 1 {
					reqs.Subject = detail.Material[0].Subject
					reqs.Name = detail.Material[0].Name
					reqs.Cover = detail.Material[0].Cover
					reqs.Introduction = detail.Material[0].Introduction
				}

			}
			err = ss.Insert(&reqs)
			if err != nil {
				xlog.Error(err)
				return err
			}

		}

	} else {
		return errors.New("余额不足")
	}
	return nil
}

func (e *ApiStudent) GetMyInviteList(c *dto.MyInviteStudentListGetPageReq, myId int, list *[]models.MyInviteStudentList, count *int64) error {
	var err error
	var student models.SysStudent
	err = e.Orm.Debug().Preload("College").
		Scopes(
			cDto.Paginate(c.GetPageSize(), c.GetPageIndex()),
		).Table(student.TableName()).Where("recommender = ?", myId).Find(list).Limit(-1).Offset(-1).
		Count(count).Error
	if err != nil {
		return err
	}
	return nil

}

func (e *ApiStudent) Chronography(studentID int, c *dto.ChronographyReq) error {
	var err error
	var model models.SysStudent
	var durationModel models.SysStudyDuration

	if c.TimeType == "start" {
		err = e.Orm.Where("student_id = ?", studentID).First(&durationModel).Error
		if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
			var data models.SysStudyDuration
			data.StartTime = time.Now().Unix()
			data.StudentId = studentID
			err = e.Orm.Debug().Model(durationModel).Create(&data).Error
			if err != nil {
				return err
			}
			return nil
		}
		updates := make(map[string]interface{})
		updates["start_time"] = time.Now().Unix()
		updates["status"] = 1
		err = e.Orm.Debug().Model(durationModel).Where("student_id = ?", studentID).Updates(updates).Error
		if err != nil {
			return err
		}
		return nil
	} else if c.TimeType == "stop" {
		var data models.UpdateStudyDurationModel
		var durationModels models.SysStudyDuration

		err = e.Orm.Where("student_id = ?", studentID).First(&durationModels).Error
		if err != nil {
			return err
		}

		if durationModels.Status == 0 {
			return errors.New("学习暂未开始，无法停止")
		}
		err = e.Orm.Debug().Where("id = ?", studentID).Find(&data).Error
		if err != nil {
			return err
		}

		tmpDuration := time.Now().Unix() - durationModels.StartTime
		duration := int64(data.StudyDuration) + tmpDuration

		return e.Orm.Transaction(func(tx *gorm.DB) error {
			err = tx.Model(model).Where("id = ?", studentID).Update("study_duration", duration).Error
			if err != nil {
				return err
			}
			err = tx.Model(durationModels).Where("student_id = ?", studentID).Update("status", 0).Error
			if err != nil {
				return err
			}
			return nil
		})

	} else {
		return errors.New("参数错误")
	}
	return nil
}

type AddScore struct {
	BuyerId     int     `json:"buyer_id"`
	OrderNumber string  `json:"order_number"`
	ScoreChange float64 `json:"score_change"`
	Change      int     `json:"change"`
	//商品类型OnlineOrder，MaterialOrder,LiveOrder
	OrderType string `json:"order_type"`
}
